#include "ExampleAIModule.h"
using namespace BWAPI;

void ExampleAIModule::onStart()
{
	Broodwar->printf("The map is %s, a %d player map",Broodwar->mapName().c_str(),Broodwar->getStartLocations().size());
	// Enable some cheat flags
	Broodwar->enableFlag(Flag::UserInput);
	//Broodwar->setLocalSpeed(100);
	// Uncomment to enable complete map information
	//Broodwar->enableFlag(Flag::CompleteMapInformation);

	//read map information into BWTA so terrain analysis can be done in another thread
	BWTA::readMap();
	analyzed=false;
	analysis_just_finished=false;
	show_stats=false;

	show_visibility_data=false;
	show_attack_lines=true;
	show_move_paths=true;
	show_formations=true;
	show_idle=true;
	show_enemy_sight_range = true;
	show_enemy_attack_range = true;

	auto_gather = true;

	if (Broodwar->isReplay())
	{
		Broodwar->printf("The following players are in this replay:");
		for(std::set<Player*>::iterator p=Broodwar->getPlayers().begin();p!=Broodwar->getPlayers().end();p++)
		{
			if (!(*p)->getUnits().empty() && !(*p)->isNeutral())
			{
				Broodwar->printf("%s, playing as a %s",(*p)->getName().c_str(),(*p)->getRace().getName().c_str());
			}
		}
	}
	else
	{
		Broodwar->printf("Analyzing map... this may take a minute");
		CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)AnalyzeThread, NULL, 0, NULL);
		for(std::set<Unit*>::const_iterator i=Broodwar->self()->getUnits().begin();i!=Broodwar->self()->getUnits().end();i++)
		{
			if ((*i)->isIdle())
			{
				//send each worker to the mineral field that is closest to it
				if ((*i)->getType().isWorker())
					ai::mineNearestMineral(*i);
				else if ((*i)->getType().isResourceDepot())
				{
					//if this is a center, tell it to build the appropiate type of worker
					if ((*i)->getType().getRace()!=Races::Zerg)
					{
						(*i)->train(*Broodwar->self()->getRace().getWorker());
					}
					else //if we are Zerg, we need to select a larva and morph it into a drone
					{
						std::set<Unit*> myLarva=(*i)->getLarva();
						if (myLarva.size()>0)
						{
							Unit* larva=*myLarva.begin();
							larva->morph(UnitTypes::Zerg_Drone);
						}
					}
				}
			}
		}
	}
}
void ExampleAIModule::onEnd(bool isWinner)
{
	if (isWinner)
	{
		Broodwar->sendText("I win! I win! :P");
	}
	Broodwar->sendText("Good game :)");
}
void ExampleAIModule::onFrame()
{
	if (show_visibility_data)
	{
		for(int x=0;x<Broodwar->mapWidth();x++)
		{
			for(int y=0;y<Broodwar->mapHeight();y++)
			{
				if (Broodwar->isExplored(x,y))
				{
					if (Broodwar->isVisible(x,y))
						Broodwar->drawDotMap(x*32+16,y*32+16,Colors::Green);
					else
						Broodwar->drawDotMap(x*32+16,y*32+16,Colors::Blue);
				}
				else
					Broodwar->drawDotMap(x*32+16,y*32+16,Colors::Red);
			}
		}
	}

	if (Broodwar->isReplay())
		return;

	if(show_stats)
		drawStats();

	std::set<Unit*> enemyUnits;

	for(std::set<Unit*>::iterator m = Broodwar->getAllUnits().begin();m != Broodwar->getAllUnits().end(); ++m)
	{
		if ((*m)->getPlayer()->isEnemy(Broodwar->self()))
		{
			enemyUnits.insert((*m));
		}
	}

	//if (Broodwar->getSelectedUnits().begin() != Broodwar->getSelectedUnits().end())
	//      Broodwar->drawTextScreen(5,16,"Coolddown: (%i) (%i)", (*Broodwar->getSelectedUnits().begin())->getGroundWeaponCooldown(), (*Broodwar->getSelectedUnits().begin())->getAirWeaponCooldown());
	//if (Broodwar->getFrameCount()%10 == 0)
	//      getDragoons()->setCenter(getDragoons()->getCenter() + BWAPI::Position(1, 0));

	std::vector<CFormation*> formations = CFormation::getFormations();
	for (int i = 0; i < formations.size(); ++i)
	{
		if (Broodwar->getFrameCount()%30 == 0)
			formations[i]->recalculateSlots();
		if (show_formations)
		{
			Broodwar->drawCircle(CoordinateType::Map, formations[i]->getCenter().x(), formations[i]->getCenter().y(), 3, Colors::Yellow, true);
			for (int j = 0; j < formations[i]->getUnits().size(); ++j)
			{
				BWAPI::Position pos = formations[i]->getPosition(j);
				Broodwar->drawCircle(CoordinateType::Map, pos.x(), pos.y(), 2, Colors::Green, true);
			}
			if (Unit* target = formations[i]->getTarget())
				Broodwar->drawLine(CoordinateType::Map,
				formations[i]->getCenter().x(), formations[i]->getCenter().y(),
				target->getPosition().x(), target->getPosition().y(),
				Colors::Red);
		}
		for(std::set<Unit*>::iterator m = enemyUnits.begin();m != enemyUnits.end(); ++m)
		{
			if (formations[i]->getTarget() == 0 || ((*m)->getDistance(formations[i]->getCenter()) < formations[i]->getTarget()->getDistance(formations[i]->getCenter())))
				if ((*m)->getDistance(formations[i]->getCenter()) < 1500)
					formations[i]->setTarget(*m);
		}
	}
	for(std::set<Unit*>::const_iterator i = enemyUnits.begin(); i != enemyUnits.end(); i++)
	{
		Position pos=(*i)->getPosition();

		//Drawing
		if (show_enemy_sight_range)
		{
			int radius = (*i)->getType().sightRange();
			Broodwar->drawCircle(CoordinateType::Map, pos.x(), pos.y(), radius, Colors::Grey);
		}
		if (show_enemy_attack_range)
		{
			int radius;
			radius = (*i)->getType().airWeapon()->maxRange();
			Broodwar->drawCircle(CoordinateType::Map, pos.x(), pos.y(), radius, Colors::Cyan);
			radius = (*i)->getType().groundWeapon()->maxRange();
			Broodwar->drawCircle(CoordinateType::Map, pos.x(), pos.y(), radius, Colors::Red);
		}
	}
	for(std::set<Unit*>::const_iterator i = Broodwar->self()->getUnits().begin(); i != Broodwar->self()->getUnits().end(); i++)
	{
		Position pos=(*i)->getPosition();
		CFormation *group = CFormation::getFormation((*i));

		if ((*i)->isBeingConstructed() && (((*i)->getType().maxShields() > 0 && (*i)->getShields() == 0) || (*i)->getHitPoints() < (*i)->getInitialHitPoints()))
			(*i)->cancelConstruction();

		if (false) //Use Experimental Zealot Attack algorithm
		{
			//ZEALOT ATTACK ROUTINE
			if ((*i)->getType().getID() == 65 && Broodwar->getFrameCount()%28==0 && (!(*i)->getGroundWeaponCooldown()))
			{
				Unit* target = 0;
				double smallestDeath = 100000;

				if (!enemyUnits.empty() && !(*i)->isStartingAttack()){
					for(std::set<Unit*>::const_iterator j = enemyUnits.begin(); j != enemyUnits.end(); j++){
						double deathCounter = (*j)->getHitPoints() + (*j)->getShields(); //Is negative, if target dies before unit can land a blow. Is small if unit is about to die soon (priority target). (NOW WORKS, DON'T BREAK!)
						int killerCounter = 0; //Calculates how many attackers are currently attacking the could-be-target. (IS NEEDED, UNTIL WE FIGURE OUT, HOW TO FIND OUT IF THERE IS ROOM TO ATTACK)
						double dps = 0;
						for(std::set<Unit*>::const_iterator k=Broodwar->self()->getUnits().begin();k!=Broodwar->self()->getUnits().end();k++){
							if ((*k)->getTarget() == (*j) && (*k)->getDistance(*j) < 50){
								dps += (*k)->getType().groundWeapon()->damageAmount()/(*k)->getType().groundWeapon()->damageCooldown();
								if ((*k)->getType().getID() == 65){
									killerCounter++;
								}
							}
						}

						dps = dps * ((*i)->getDistance(*j) / (*i)->getType().topSpeed());
						deathCounter -= dps;

						if ((*i)->getDistance(*j) > 50){
							deathCounter += 1000;  //So the unit will priorize close targets (perhaps not needed anymore?)
						}


						if (deathCounter < smallestDeath && deathCounter > 0 && killerCounter < 4){
							if (deathCounter > 0){
								smallestDeath = deathCounter;
							}
							target = (*j);
						}
					}

					if (target){
						(*i)->attackUnit(target);
					}
					if (target && ((*i)->getDistance(target) > 20)){ //If the target is not adjacent -> attackMove, so if target is unreachable, a new target is automatically selected.
						(*i)->attackMove(target->getPosition());
					}
				}
			}
		}
		if (false) //Use Experimental Dragoon Attack algorithm
		{
			// DRAGOON ATTACK ROUTINE
			// The same, but the distance to enemy is not considered in deathCounter, and the killerCounter is removed.
			if ((*i)->getType().getID() == 66 && Broodwar->getFrameCount()%12==0 && (!(*i)->getGroundWeaponCooldown()))
			{
				Unit* target = 0;
				double smallestDeath = 100000;

				if (!enemyUnits.empty() && !(*i)->isStartingAttack()){
					for(std::set<Unit*>::const_iterator j = enemyUnits.begin(); j != enemyUnits.end(); j++){
						double deathCounter = (*j)->getHitPoints() + (*j)->getShields();
						double dps = 0;
						for(std::set<Unit*>::const_iterator k=Broodwar->self()->getUnits().begin();k!=Broodwar->self()->getUnits().end();k++){
							if ((*k)->getTarget() == (*j)){
								dps += (*k)->getType().groundWeapon()->damageAmount()/(*k)->getType().groundWeapon()->damageCooldown();							
							}
						}
					
						dps = dps * ((*i)->getType().groundWeapon()->damageCooldown()); //Don't attack if you cannot make the difference during 1 complete dragoon attack (while ally zealots and dragoons are attacking).
						deathCounter -= dps;

						if ((*i)->getDistance(*j) > (*i)->getType().groundWeapon()->maxRange()*6/4 + 40){
							deathCounter += 1000;  //The unit priorizes targets that are in range, or just slightly out of range
						}

						if (deathCounter < smallestDeath && deathCounter > 0){
							if (deathCounter > 0){
								smallestDeath = deathCounter;
							}
							target = (*j);
						}
					}

					if (target){
						(*i)->attackUnit(target);
					}
				}
			}
		}
		if (false) //Use Experimental Dodge algorithm
		{
			//DODGE ROUTINE
			if (!enemyUnits.empty()) // && (Broodwar->getFrameCount()%30==0))
			{
				int targetedCount = 0; // All targeters; Dodger moves away from the average position of all enemies, who target it.
				int dragoonsTargeting = 0;
				int zealotsTargeting = 0;
				int closestZealotDistance = 1000000;
				int vaistettava_x = 0;
				int vaistettava_y = 0;
				for(std::set<Unit*>::const_iterator j = enemyUnits.begin();j != enemyUnits.end(); j++){
					if ((*j)->getTarget() == (*i) || (*j)->getOrderTarget() == (*i)) {
						targetedCount++;
						if ((*j)->getType().getID() == 65){
							zealotsTargeting++;
							if ((*j)->getDistance(*i) < closestZealotDistance){
								closestZealotDistance = (*j)->getDistance(*i);
							}
						}
						else if ((*j)->getType().getID() == 66){
							dragoonsTargeting++;
						}
						vaistettava_x += (*j)->getPosition().x();
						vaistettava_y += (*j)->getPosition().y();
					}
				}

				if (targetedCount > 0)
				{
					vaistettava_x /= targetedCount;
					vaistettava_y /= targetedCount;
					vaistettava_x = (*i)->getPosition().x() - vaistettava_x;
					vaistettava_y = (*i)->getPosition().y() - vaistettava_y;
					vaistettava_x = ((*i)->getPosition().x() + vaistettava_x/3);
					vaistettava_y = ((*i)->getPosition().y() + vaistettava_y/3);

					if (
						//((*i)->getType().getID() == 65 &&
						//      (zealotsTargeting >= 3)) || //ZEALOTS: If 3 or more zealots targets you
						//DRAGOONS
						((*i)->getType().getID() == 66 && ((*i)->getShields() == 0) && ((*i)->getHitPoints() < 80) &&
						((dragoonsTargeting > 1) || (zealotsTargeting > 0 && closestZealotDistance <= 15)))
						)

					{
						Position dodge = Position(vaistettava_x, vaistettava_y);
						(*i)->rightClick(dodge);
					}
				}
			}
		}

		if (group)
		{
			if (!group->getTarget()) //|| group->getTarget()->getDistance(group->getCenter()) > group->getTarget()->getType().groundWeapon()->maxRange()*6/4 + 100)
				if (!group->isInPosition(*i) && (!(*i)->getGroundWeaponCooldown()) && (!(*i)->getAirWeaponCooldown()))
					(*i)->rightClick(group->getPosition(*i));
		}

		if ((*i)->isBeingConstructed())
		{
			double progress = 1.0 - ((static_cast<double>((*i)->getRemainingBuildTime())) / (*i)->getType().buildTime());
			drawProgressBar((*i)->getPosition(), progress, BWAPI::Colors::Red);
		}

		if ((*i)->isTraining())
		{
			if ((*i)->getRemainingTrainTime() > .0)
			{
				double progress = 1.0 - ((static_cast<double>((*i)->getRemainingTrainTime())) / (*i)->getTrainingQueue().front().buildTime());
				drawProgressBar((*i)->getPosition(), progress, BWAPI::Colors::Green);
			}
		}

		if ((*i)->isResearching() > 0)
		{
			double progress = 1.0 - ((static_cast<double>((*i)->getRemainingResearchTime())) / (*i)->getTrainingQueue().front().buildTime());
			drawProgressBar((*i)->getPosition(), progress, BWAPI::Colors::Cyan);
		}

		if ((*i)->isUpgrading() > 0)
		{
			double progress = 1.0 - ((static_cast<double>((*i)->getRemainingUpgradeTime())) / 
				((*i)->getUpgrade().upgradeTimeBase()+(*i)->getUpgrade().upgradeTimeFactor()*Broodwar->self()->getUpgradeLevel((*i)->getUpgrade())));
			drawProgressBar((*i)->getPosition(), progress, BWAPI::Colors::Yellow);
		}

		//if (analyzed && Broodwar->getFrameCount()%30==0)
		//{
		//      //order one of our workers to guard our chokepoint.
		//      if ((*i)->getType().isWorker())
		//      {
		//              //get the chokepoints linked to our home region
		//              std::set<BWTA::Chokepoint*> chokepoints= home->getChokepoints();
		//              double min_length=10000;
		//              BWTA::Chokepoint* choke=NULL;

		//              //iterate through all chokepoints and look for the one with the smallest gap (least width)
		//              for(std::set<BWTA::Chokepoint*>::iterator c=chokepoints.begin();c!=chokepoints.end();c++)
		//              {
		//                      double length=(*c)->getWidth();
		//                      if (length<min_length || choke==NULL)
		//                      {
		//                              min_length=length;
		//                              choke=*c;
		//                      }
		//              }

		//              //order the worker to move to the center of the gap
		//              (*i)->rightClick(choke->getCenter());
		//      }
		//}

		if ((*i)->isIdle())
		{
			//if ((*i)->isIdle() && (*i)->getType().canProduce())
			//{
			//	//if this is a center, tell it to build the appropiate type of worker
			//	if ((*i)->getType().getRace()!=Races::Zerg)
			//	{
			//		(*i)->train(*Broodwar->self()->getRace().getWorker());
			//	}
			//	else //if we are Zerg, we need to select a larva and morph it into a drone
			//	{
			//		std::set<Unit*> myLarva=(*i)->getLarva();
			//		if (myLarva.size()>0)
			//		{
			//			Unit* larva=*myLarva.begin();
			//			larva->morph(UnitTypes::Zerg_Drone);
			//		}
			//	}
			//}
			if (auto_gather && (Broodwar->getFrameCount()%50 == 0))
				if ((*i)->isIdle() && (*i)->getType().isWorker())
					ai::mineNearestMineral(*i);
			if (show_idle)
				if ((*i)->isIdle())
				{
					Broodwar->drawCircle(CoordinateType::Map, (*i)->getPosition().x(), (*i)->getPosition().y(), 10, Colors::Yellow, false);
					//if (!(*i)->getType().isBuilding() && (Broodwar->getFrameCount()%100 == 0))
					//      Broodwar->printf("A %s is sitting idle at (%d,%d)", (*i)->getType().getName().c_str(), (*i)->getPosition().x(), (*i)->getPosition().y());
				}
		}

		//Drawing
		if (show_move_paths)
		{
			Position point2 = (*i)->getTargetPosition();
			Broodwar->drawLine(CoordinateType::Map, pos.x(), pos.y(), point2.x(), point2.y(), Colors::Green);
		}
		if (show_attack_lines)
			if (Unit *target = (*i)->getTarget())
			{
				Position point2 = target->getPosition();
				Broodwar->drawLine(CoordinateType::Map, pos.x(), pos.y(), point2.x(), point2.y(), Colors::Red);
			}
	}
	if (analyzed)
	{
		//we will iterate through all the base locations, and draw their outlines.
		for(std::set<BWTA::BaseLocation*>::const_iterator i = BWTA::getBaseLocations().begin();i != BWTA::getBaseLocations().end(); ++i)
		{
			TilePosition p = (*i)->getTilePosition();
			Position c = (*i)->getPosition();

			//draw outline of center location
			Broodwar->drawBox(CoordinateType::Map,p.x()*32,p.y()*32,p.x()*32+4*32,p.y()*32+3*32,Colors::Blue,false);


			//draw a circle at each mineral patch
			for(std::set<BWAPI::Unit*>::const_iterator j=(*i)->getStaticMinerals().begin();j!=(*i)->getStaticMinerals().end();j++)
			{
				Position q=(*j)->getInitialPosition();
				Broodwar->drawCircle(CoordinateType::Map,q.x(),q.y(),30,Colors::Cyan,false);
			}

			//draw the outlines of vespene geysers
			for(std::set<BWAPI::Unit*>::const_iterator j=(*i)->getGeysers().begin();j!=(*i)->getGeysers().end();j++)
			{
				TilePosition q=(*j)->getInitialTilePosition();
				Broodwar->drawBox(CoordinateType::Map,q.x()*32,q.y()*32,q.x()*32+4*32,q.y()*32+2*32,Colors::Orange,false);
			}

			//if this is an island expansion, draw a yellow circle around the base location
			if ((*i)->isIsland())
			{
				Broodwar->drawCircle(CoordinateType::Map,c.x(),c.y(),80,Colors::Yellow,false);
			}
		}

		//we will iterate through all the regions and draw the polygon outline of it in green.
		for(std::set<BWTA::Region*>::const_iterator r=BWTA::getRegions().begin();r!=BWTA::getRegions().end();r++)
		{
			BWTA::Polygon p=(*r)->getPolygon();
			//TODO:
			//BWAPI::Color color = Colors::Grey; //Unsecure
			//if (CInformationManager::isSecured(*r))
			//	color = Colors::Green; //Secure
			//if (CInformationManager::isUnsafe(*r))
			//	color = Colors::Red; //Unsafe
			for(int j=0;j<(int)p.size();j++)
			{
				Position point1=p[j];
				Position point2=p[(j+1) % p.size()];
				Broodwar->drawLine(CoordinateType::Map, point1.x(), point1.y(), point2.x(), point2.y(), color);
			}
		}

		//we will visualize the chokepoints with red lines
		for(std::set<BWTA::Region*>::const_iterator r=BWTA::getRegions().begin();r!=BWTA::getRegions().end();r++)
		{
			for(std::set<BWTA::Chokepoint*>::const_iterator c=(*r)->getChokepoints().begin();c!=(*r)->getChokepoints().end();c++)
			{
				Position point1 = (*c)->getSides().first;
				Position point2 = (*c)->getSides().second;
				Position center = (*c)->getCenter();
				//Broodwar->drawLine(CoordinateType::Map, point1.x(), point1.y(), point2.x(), point2.y(), Colors::Red);
				Broodwar->drawCircle(CoordinateType::Map, center.x(), center.y(), (*c)->getWidth()/2, Colors::Red, false);
			}
		}
	}
	if (analysis_just_finished)
	{
		Broodwar->printf("Finished analyzing map.");
		analysis_just_finished=false;

		//if (Broodwar->self()->getStartLocation().x() < 1000){
		//	if (dragoons)
		//		dragoons->setCenter(dragoons->getCenter() + BWAPI::Position(200,0));
		//	if (zealots)
		//		zealots->setCenter(dragoons->getCenter() + BWAPI::Position(250,0));
		//}
		//else {
		//	if (dragoons)
		//		dragoons->setCenter(dragoons->getCenter() + BWAPI::Position(-200,0));
		//	if (zealots)
		//		zealots->setCenter(dragoons->getCenter() + BWAPI::Position(-250,0));
		//}

		//Create patrol waypoints
		//Position center;
		//for(std::set<BWTA::Region*>::const_iterator r=BWTA::getRegions().begin();r!=BWTA::getRegions().end();r++)
		//{
		//	if (center.x 
		//	Broodwar->printf("(%d, %d)",center.x(), center.y());
		//}
		//	Position wayPointlb = Position (center.x()-(18*32), center.y());
		//	Position wayPointrb = Position (center.x()+(18*32), center.y());

		//	if (Broodwar->self()->getStartLocation().x() > center.x()){
		//		dragoons->setCenter(wayPointrb);
		//	}
		//	else if (Broodwar->self()->getStartLocation().x() < center.x()){
		//		dragoons->setCenter(wayPointlb);
		//	}


		//	//dragoons->addWayPoint(wayPoint);

		//	Position secwayPoint = Position (center.x()-(18*32), center.y());

		//	
		//	//BWTA::Polygon p=;
		//	//for(int j=0;j<(int)p.size();j++)
		//	//{
		//	//	Position point1=p[j];
		//	//	Position point2=p[(j+1) % p.size()];
		//	//	Broodwar->drawLine(CoordinateType::Map,point1.x(),point1.y(),point2.x(),point2.y(),Colors::Green);
		//	//}
		//}
	}
}

void ExampleAIModule::onUnitCreate(BWAPI::Unit* unit)
{
	if (!Broodwar->isReplay())
	{
		Broodwar->printf("A %s [%x] has been created at (%d,%d)",unit->getType().getName().c_str(),unit,unit->getPosition().x(),unit->getPosition().y());
		if (unit->getPlayer() == Broodwar->self())
		{
			if (auto_gather)
				if (unit->getType().isWorker())
					ai::mineNearestMineral(unit);
		}
	}
	else
	{
		/*if we are in a replay, then we will print out the build order
		(just of the buildings, not the units).*/
		if (unit->getType().isBuilding() && unit->getPlayer()->isNeutral()==false)
		{
			int seconds=Broodwar->getFrameCount()/24;
			int minutes=seconds/60;
			seconds%=60;
			Broodwar->printf("%.2d:%.2d: %s creates a %s",minutes,seconds,unit->getPlayer()->getName().c_str(),unit->getType().getName().c_str());
		}
	}
}
void ExampleAIModule::onUnitDestroy(BWAPI::Unit* unit)
{
	if (!Broodwar->isReplay())
	{
		if (unit->getPlayer()->isEnemy(Broodwar->self()))
			Broodwar->printf("\x07 A %s [%x] has been destroyed at (%d,%d)",unit->getType().getName().c_str(),unit,unit->getPosition().x(),unit->getPosition().y());
		else
			Broodwar->printf("\x08 A %s [%x] has been destroyed at (%d,%d)",unit->getType().getName().c_str(),unit,unit->getPosition().x(),unit->getPosition().y());
		if (CFormation *group = CFormation::getFormation(unit))
			group->leaveFormation(unit);
	}
}

void ExampleAIModule::onUnitMorph(BWAPI::Unit* unit)
{
	if (!Broodwar->isReplay())
	{
		if (unit->getPlayer()->isEnemy(Broodwar->self()))
			Broodwar->printf("\x11 A %s [%x] has been morphed at (%d,%d)",unit->getType().getName().c_str(),unit,unit->getPosition().x(),unit->getPosition().y());
		else
			Broodwar->printf("A %s [%x] has been morphed at (%d,%d)",unit->getType().getName().c_str(),unit,unit->getPosition().x(),unit->getPosition().y());
		if (unit->getPlayer() == Broodwar->self())
		{
			if (auto_gather)
				if (unit->getType().isWorker())
					ai::mineNearestMineral(unit);
		}
	}
	else
	{
		/*if we are in a replay, then we will print out the build order
		(just of the buildings, not the units).*/
		if (unit->getType().isBuilding() && unit->getPlayer()->isNeutral()==false)
		{
			int seconds=Broodwar->getFrameCount()/24;
			int minutes=seconds/60;
			seconds%=60;
			Broodwar->printf("%.2d:%.2d: %s morphs a %s",minutes,seconds,unit->getPlayer()->getName().c_str(),unit->getType().getName().c_str());
		}
	}
}
void ExampleAIModule::onUnitShow(BWAPI::Unit* unit)
{
	if (!Broodwar->isReplay())
		if (unit->getPlayer()->isEnemy(Broodwar->self()))
			Broodwar->printf("\x11 A %s [%x] has been spotted at (%d,%d)",unit->getType().getName().c_str(),unit,unit->getPosition().x(),unit->getPosition().y());
}
void ExampleAIModule::onUnitHide(BWAPI::Unit* unit)
{
	if (!Broodwar->isReplay())
		if (unit->getPlayer()->isEnemy(Broodwar->self()))
		{
			//TODO: Create ghost system (unit memory)
			//addGhost(unit->getType(), unit->getPosition());

			//Broodwar->printf("\x08 A %s [%x] was last seen at (%d,%d)",unit->getType().getName().c_str(),unit,unit->getPosition().x(),unit->getPosition().y());
		}
}
void ExampleAIModule::onUnitRenegade(BWAPI::Unit* unit)
{
	if (!Broodwar->isReplay())
		Broodwar->printf("\x10 A %s [%x] is now owned by %s",unit->getType().getName().c_str(),unit,unit->getPlayer()->getName().c_str());
}
void ExampleAIModule::onPlayerLeft(BWAPI::Player* player)
{
	Broodwar->printf("%s left the game.",player->getName().c_str());
}
void ExampleAIModule::onNukeDetect(BWAPI::Position target)
{
	if (target!=Positions::Unknown)
	{
		Broodwar->printf("Nuclear Launch Detected at (%d,%d)",target.x(),target.y());
		Broodwar->pingMinimap(target);
	}
	else
		Broodwar->printf("Nuclear Launch Detected.  Fortunately, it doesn't seem to have been pointed at us.");
	Broodwar->sendText("NUKE!");
}

bool ExampleAIModule::onSendText(std::string text)
{
	if (text=="/show players")
	{
		showPlayers();
		return false;
	} else if (text=="/show forces")
	{
		showForces();
		return false;
	} else if (!uiCommands(text)) {
		return false;
	} else if (!aiCommands(text)) {
		return false;
	} else if (!formationCommands(text)) {
		return false;
	} else if (text=="/analyze")
	{
		if (analyzed == false)
		{
			Broodwar->printf("Analyzing map... this may take a minute");
			CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)AnalyzeThread, NULL, 0, NULL);
		}
		return false;
	} else
	{
	}
	return true;
}

bool ExampleAIModule::aiCommands(std::string text)
{
	if ((text=="/auto gather") || (text=="/auto gather on"))
	{
		auto_gather=true;
		return false;
	}
	else if (text=="/auto gather off")
	{
		auto_gather=false;
		return false;
	}
	return true;
}


bool ExampleAIModule::uiCommands(std::string text)
{
	if (text=="/show visibility")
	{
		show_visibility_data=true;
		return false;
	} else if (text=="/show idle")
	{
		show_idle=true;
		return false;
	} else if (text=="/hide idle")
	{
		show_idle=false;
		return false;
	} else if (text=="/show enemy sight range")
	{
		show_enemy_sight_range=true;
		return false;
	} else if (text=="/hide enemy sight range")
	{
		show_enemy_sight_range=false;
		return false;
	} else if (text=="/show enemy attack range")
	{
		show_enemy_attack_range=true;
		return false;
	} else if (text=="/hide enemy attack range")
	{
		show_enemy_attack_range=false;
		return false;
	} else if (text=="/show targets")
	{
		show_attack_lines=true;
		return false;
	} else if (text=="/hide targets")
	{
		show_attack_lines=false;
		return false;
	} else if (text=="/show paths")
	{
		show_move_paths=true;
		return false;
	} else if (text=="/hide paths")
	{
		show_move_paths=false;
		return false;
	} else if (text=="/show formations")
	{
		show_formations=true;
		return false;
	} else if (text=="/hide formations")
	{
		show_formations=false;
		return false;
	}
	return true;
}

bool ExampleAIModule::formationCommands(std::string text)
{
	if (text=="/fmt join")
	{
		if (Broodwar->getSelectedUnits().size())
		{
			CFormation* formation = 0;
			for(std::set<BWAPI::Unit*>::const_iterator i = Broodwar->getSelectedUnits().begin(); i != Broodwar->getSelectedUnits().end(); ++i)
			{
				if (!formation)
					if (formation = CFormation::getFormation(*i))
						break;
			}
			if (!formation)
				formation = CFormation::getEmptyFormation(Broodwar->getMousePosition() + Broodwar->getScreenPosition());
			for(std::set<BWAPI::Unit*>::const_iterator i = Broodwar->getSelectedUnits().begin(); i != Broodwar->getSelectedUnits().end(); ++i)
			{
				formation->joinFormation(*i);
			}
		}
		return false;
	} else if (text=="/fmt leave")
	{
		if (Broodwar->getSelectedUnits().size())
			for(std::set<BWAPI::Unit*>::const_iterator i = Broodwar->getSelectedUnits().begin(); i != Broodwar->getSelectedUnits().end(); ++i)
				if (CFormation* formation = CFormation::getFormation(*i))
					formation->leaveFormation(*i);
		return false;
	} else if (text=="/fmt disband")
	{
		if (Broodwar->getSelectedUnits().size())
			for(std::set<BWAPI::Unit*>::const_iterator i = Broodwar->getSelectedUnits().begin(); i != Broodwar->getSelectedUnits().end(); ++i)
				if (CFormation* formation = CFormation::getFormation(*i))
					formation->disbandFormation();
		return false;
	} else if ((text=="/fmt move") || (text=="/fmt mv"))
	{
		if (Broodwar->getSelectedUnits().size())
			for(std::set<BWAPI::Unit*>::const_iterator i = Broodwar->getSelectedUnits().begin(); i != Broodwar->getSelectedUnits().end(); ++i)
				if (CFormation* formation = CFormation::getFormation(*i))
					formation->setCenter(Broodwar->getMousePosition() + Broodwar->getScreenPosition());
		return false;
	} else if ((text=="/fmt waypoint") || (text=="/fmt way"))
	{
		std::vector<CFormation*> formations;
		if (Broodwar->getSelectedUnits().size())
		{
			for(std::set<BWAPI::Unit*>::const_iterator i = Broodwar->getSelectedUnits().begin(); i != Broodwar->getSelectedUnits().end(); ++i)
				if (CFormation* formation = CFormation::getFormation(*i))
					formations.push_back(formation);
			for (int i = 0; i < formations.size(); ++i)
				formations[i]->addWayPoint(Broodwar->getMousePosition() + Broodwar->getScreenPosition());
		}
		return false;
	} else if (text=="/fmt none")
	{
		if (Broodwar->getSelectedUnits().size())
			for(std::set<BWAPI::Unit*>::const_iterator i = Broodwar->getSelectedUnits().begin(); i != Broodwar->getSelectedUnits().end(); ++i)
				if (CFormation* formation = CFormation::getFormation(*i))
					formation->setFormation(ZFNone);
		return false;
	} else if (text=="/fmt v")
	{
		if (Broodwar->getSelectedUnits().size())
			for(std::set<BWAPI::Unit*>::const_iterator i = Broodwar->getSelectedUnits().begin(); i != Broodwar->getSelectedUnits().end(); ++i)
				if (CFormation* formation = CFormation::getFormation(*i))
					formation->setFormation(ZFVLine);
		return false;
	} else if (text=="/fmt h")
	{
		if (Broodwar->getSelectedUnits().size())
			for(std::set<BWAPI::Unit*>::const_iterator i = Broodwar->getSelectedUnits().begin(); i != Broodwar->getSelectedUnits().end(); ++i)
				if (CFormation* formation = CFormation::getFormation(*i))
					formation->setFormation(ZFHLine);
		return false;
	} else if (text=="/fmt vv")
	{
		if (Broodwar->getSelectedUnits().size())
			for(std::set<BWAPI::Unit*>::const_iterator i = Broodwar->getSelectedUnits().begin(); i != Broodwar->getSelectedUnits().end(); ++i)
				if (CFormation* formation = CFormation::getFormation(*i))
					formation->setFormation(ZFDoubleVLine);
		return false;
	} else if (text=="/fmt vvd")
	{
		if (Broodwar->getSelectedUnits().size())
			for(std::set<BWAPI::Unit*>::const_iterator i = Broodwar->getSelectedUnits().begin(); i != Broodwar->getSelectedUnits().end(); ++i)
				if (CFormation* formation = CFormation::getFormation(*i))
					formation->setFormation(ZFDoubleVLineDense);
		return false;
	} else if (text=="/fmt hh")
	{
		if (Broodwar->getSelectedUnits().size())
			for(std::set<BWAPI::Unit*>::const_iterator i = Broodwar->getSelectedUnits().begin(); i != Broodwar->getSelectedUnits().end(); ++i)
				if (CFormation* formation = CFormation::getFormation(*i))
					formation->setFormation(ZFDoubleHLine);
		return false;
	} else if (text=="/fmt hhd")
	{
		if (Broodwar->getSelectedUnits().size())
			for(std::set<BWAPI::Unit*>::const_iterator i = Broodwar->getSelectedUnits().begin(); i != Broodwar->getSelectedUnits().end(); ++i)
				if (CFormation* formation = CFormation::getFormation(*i))
					formation->setFormation(ZFDoubleHLineDense);
		return false;
	} else if ((text=="/fmt /") || (text=="/fmt fore"))
	{
		if (Broodwar->getSelectedUnits().size())
			for(std::set<BWAPI::Unit*>::const_iterator i = Broodwar->getSelectedUnits().begin(); i != Broodwar->getSelectedUnits().end(); ++i)
				if (CFormation* formation = CFormation::getFormation(*i))
					formation->setFormation(ZFForeslash);
		return false;
	} else if ((text=="/fmt \\") || (text=="/fmt back"))
	{
		if (Broodwar->getSelectedUnits().size())
			for(std::set<BWAPI::Unit*>::const_iterator i = Broodwar->getSelectedUnits().begin(); i != Broodwar->getSelectedUnits().end(); ++i)
				if (CFormation* formation = CFormation::getFormation(*i))
					formation->setFormation(ZFBackslash);
		return false;
	} else if (text=="/fmt x")
	{
		if (Broodwar->getSelectedUnits().size())
			for(std::set<BWAPI::Unit*>::const_iterator i = Broodwar->getSelectedUnits().begin(); i != Broodwar->getSelectedUnits().end(); ++i)
				if (CFormation* formation = CFormation::getFormation(*i))
					formation->setFormation(ZFCross);
		return false;
	} else if (text=="/fmt +")
	{
		if (Broodwar->getSelectedUnits().size())
			for(std::set<BWAPI::Unit*>::const_iterator i = Broodwar->getSelectedUnits().begin(); i != Broodwar->getSelectedUnits().end(); ++i)
				if (CFormation* formation = CFormation::getFormation(*i))
					formation->setFormation(ZFPlus);
		return false;
	} else if (text=="/fmt box")
	{
		if (Broodwar->getSelectedUnits().size())
			for(std::set<BWAPI::Unit*>::const_iterator i = Broodwar->getSelectedUnits().begin(); i != Broodwar->getSelectedUnits().end(); ++i)
				if (CFormation* formation = CFormation::getFormation(*i))
					formation->setFormation(ZFBox);
		return false;
	} else if (text=="/fmt block")
	{
		if (Broodwar->getSelectedUnits().size())
			for(std::set<BWAPI::Unit*>::const_iterator i = Broodwar->getSelectedUnits().begin(); i != Broodwar->getSelectedUnits().end(); ++i)
				if (CFormation* formation = CFormation::getFormation(*i))
					formation->setFormation(ZFBlock);
		return false;
	} else if (text=="/fmt diamond")
	{
		if (Broodwar->getSelectedUnits().size())
			for(std::set<BWAPI::Unit*>::const_iterator i = Broodwar->getSelectedUnits().begin(); i != Broodwar->getSelectedUnits().end(); ++i)
				if (CFormation* formation = CFormation::getFormation(*i))
					formation->setFormation(ZFDiamond);
		return false;
	} else if ((text=="/fmt circle") || (text=="/fmt o"))
	{
		if (Broodwar->getSelectedUnits().size())
			for(std::set<BWAPI::Unit*>::const_iterator i = Broodwar->getSelectedUnits().begin(); i != Broodwar->getSelectedUnits().end(); ++i)
				if (CFormation* formation = CFormation::getFormation(*i))
					formation->setFormation(ZFCircle);
		return false;
	}
	return true;
}

DWORD WINAPI AnalyzeThread()
{
	BWTA::analyze();
	analyzed   = true;
	analysis_just_finished = true;

	//self start location only available if the map has base locations
	if (BWTA::getStartLocation(BWAPI::Broodwar->self())!=NULL)
	{
		home       = BWTA::getStartLocation(BWAPI::Broodwar->self())->getRegion();
	}
	//enemy start location only available if Complete Map Information is enabled.
	if (BWTA::getStartLocation(BWAPI::Broodwar->enemy())!=NULL)
	{
		enemy_base = BWTA::getStartLocation(BWAPI::Broodwar->enemy())->getRegion();
	}
	return 0;
}

void ExampleAIModule::drawStats()
{
	std::set<Unit*> myUnits = Broodwar->self()->getUnits();
	Broodwar->drawTextScreen(5,0,"I have %d units:",myUnits.size());
	std::map<UnitType, int> unitTypeCounts;
	for(std::set<Unit*>::iterator i=myUnits.begin();i!=myUnits.end();i++)
	{
		if (unitTypeCounts.find((*i)->getType())==unitTypeCounts.end())
		{
			unitTypeCounts.insert(std::make_pair((*i)->getType(),0));
		}
		unitTypeCounts.find((*i)->getType())->second++;
	}
	int line=1;
	for(std::map<UnitType,int>::iterator i=unitTypeCounts.begin();i!=unitTypeCounts.end();i++)
	{
		Broodwar->drawTextScreen(5,16*line,"- %d %ss",(*i).second, (*i).first.getName().c_str());
		line++;
	}
}


void ExampleAIModule::showPlayers()
{
	std::set<Player*> players=Broodwar->getPlayers();
	for(std::set<Player*>::iterator i=players.begin();i!=players.end();i++)
	{
		Broodwar->printf("Player [%d]: %s is in force: %s",(*i)->getID(),(*i)->getName().c_str(), (*i)->getForce()->getName().c_str());
	}
}
void ExampleAIModule::showForces()
{
	std::set<Force*> forces=Broodwar->getForces();
	for(std::set<Force*>::iterator i=forces.begin();i!=forces.end();i++)
	{
		std::set<Player*> players=(*i)->getPlayers();
		Broodwar->printf("Force %s has the following players:",(*i)->getName().c_str());
		for(std::set<Player*>::iterator j=players.begin();j!=players.end();j++)
		{
			Broodwar->printf("  - Player [%d]: %s",(*j)->getID(),(*j)->getName().c_str());
		}
	}
}

void ExampleAIModule::drawProgressBar(BWAPI::Position pos, double progressFraction, BWAPI::Color innerBar) const
{
  const int width = 20, height = 4;
  const BWAPI::Color outline = BWAPI::Colors::Blue;
  const BWAPI::Color barBG = BWAPI::Color(0, 0, 170);
  int xLeft = pos.x() - width / 2, xRight = pos.x() + width / 2;
  int yTop = pos.y() - height / 2, yBottom = pos.y() + height / 2;
  
  //Draw outline
  Broodwar->drawLineMap(xLeft + 1, yTop, xRight - 1, yTop, outline);        //top
  Broodwar->drawLineMap(xLeft + 1, yBottom, xRight - 1, yBottom, outline);  //bottom
  Broodwar->drawLineMap(xLeft, yTop + 1, xLeft, yBottom, outline);          //left
  Broodwar->drawLineMap(xRight - 1, yTop + 1, xRight - 1, yBottom, outline);//right
  //Draw bar
  Broodwar->drawBoxMap(xLeft + 1, yTop + 1, xRight - 1, yBottom, barBG, true);
  //Draw progress bar
  const int innerWidth = (xRight - 1) - (xLeft + 1);
  int progressWidth = static_cast<int>(progressFraction * innerWidth);
  Broodwar->drawBoxMap(xLeft + 1, yTop + 1, (xLeft + 1) + progressWidth, yBottom, innerBar, true);
}